
using System;
using System.Text;
using GeoFramework;

namespace GeoFramework.Gps.Nmea
{
	/// <summary>
	/// Represents a $PGRME sentence containing positional error information.
	/// </summary>
    public class PgrmeSentence : NmeaSentence
	{
		#region Private Variables

		Distance pHorizontalPositionError;
		Distance pVerticalPositionError;
		Distance pMeanPositionError;

		#endregion

		#region Constructors

		public PgrmeSentence(string sentence) : base(sentence)
		{
			// Is the checksum valid?
			if (!IsValid && !IsPartialSentenceParsingAllowed)
			{
				pHorizontalPositionError = Distance.Empty;
				pVerticalPositionError = Distance.Empty;
				pMeanPositionError = Distance.Empty;
				// No.  Do no parsing
				return;
			}

			//$PGRME,15.0,M,45.0,M,25.0,M*22
			// where:
			//	15.0,M	   Estimated horizontal position error in metres (HPE)
			//	45.0,M	   Estimated vertical error (VPE) in metres
			//	25.0,M	   Overall spherical equivalent position error

			// This is a Garmin-proprietary sentence
			//Receiver.Device.SetManufacturer(Manufacturer.Garmin);

			try
			{
				// Extract accuracy information
				if(WordCount > 2 && Words[1].Length != 0)
				{
					pHorizontalPositionError = new Distance(
						double.Parse(Words[1], NmeaCultureInfo),
						Words[2] == "F" ? DistanceUnit.Feet : DistanceUnit.Meters);

						//
						//						double HPE = double.Parse(Words[1], NmeaCultureInfo);
						//						switch (Words[2].ToUpper(NmeaCultureInfo))
						//						{
						//							case "F":
						//								pHorizontalPositionError = new Distance(HPE, DistanceUnit.Feet).ToLocalUnitType();
						//								break;
						//							case "M":
						//								pHorizontalPositionError = new Distance(HPE, DistanceUnit.Meters).ToLocalUnitType();
						//								break;
						//						}					
					}
				else
				{
					pHorizontalPositionError = Distance.Empty;
				}

				// Extract accuracy information
				if(WordCount > 4 && Words[3].Length != 0)
				{
					pVerticalPositionError = new Distance(
						double.Parse(Words[3], NmeaCultureInfo),
						Words[4] == "F" ? DistanceUnit.Feet : DistanceUnit.Meters);

						//						double VPE = double.Parse(Words[3], NmeaCultureInfo);
						//						switch (Words[4].ToUpper(NmeaCultureInfo))
						//						{
						//							case "F":
						//								pVerticalPositionError = new Distance(VPE, DistanceUnit.Meters).ToLocalUnitType();
						//								break;
						//							case "M":
						//								pVerticalPositionError = new Distance(VPE, DistanceUnit.Meters).ToLocalUnitType();
						//								break;
						//						}					
					}
				else
				{
					pVerticalPositionError = Distance.Empty;
				}


				// Extract accuracy information
				if(WordCount > 6 && Words[5].Length != 0)
				{
					pMeanPositionError = new Distance(
						double.Parse(Words[5], NmeaCultureInfo),
						Words[6] == "F" ? DistanceUnit.Feet : DistanceUnit.Meters);

						//						double OPE = double.Parse(Words[5], NmeaCultureInfo);
						//						switch (Words[6].ToUpper(NmeaCultureInfo))
						//						{
						//							case "F":
						//								pMeanPositionError = new Distance(OPE, DistanceUnit.Meters).ToLocalUnitType();
						//								break;
						//							case "M":
						//								pMeanPositionError = new Distance(OPE, DistanceUnit.Meters).ToLocalUnitType();
						//								break;
						//						}
					}
				else
				{
					pMeanPositionError = Distance.Empty;
				}
			}
			catch(Exception ex)
			{
				throw new NmeaSentenceException(this, "A $PGRME sentence contained unrecognizable data.", ex);
			}
		}

		//[CLSCompliant(false)]
		public PgrmeSentence(Distance horizontalPositionError,
			Distance verticalPositionError,
			Distance meanPositionError)
		{
			pHorizontalPositionError = horizontalPositionError;
			pVerticalPositionError = verticalPositionError;
			pMeanPositionError = meanPositionError;
			// Now build a sentence
			StringBuilder Sentence = new StringBuilder();
			Sentence.Append("$PGRME,");
			// Append horizontal error
			Sentence.Append(HorizontalPositionError.ToMeters().ToString("d.d"));
			Sentence.Append(",M,");
			// Append vertical error
			Sentence.Append(VerticalPositionError.ToMeters().ToString("d.d"));
			Sentence.Append(",M,");
			// Append mean error
			Sentence.Append(MeanPositionError.ToMeters().ToString("d.d"));
			Sentence.Append(",M");
			// Set the sentence
			SetSentence(Sentence.ToString());
			SetChecksum();
		}

		#endregion

		#region Public Members

		public Distance HorizontalPositionError
		{
			get
			{
				return pHorizontalPositionError;
			}
		}
		
		public Distance VerticalPositionError
		{
			get
			{
				return pVerticalPositionError;
			}
		}

		public Distance MeanPositionError
		{
			get
			{
				return pMeanPositionError;
			}
		}

		/// <summary>
		/// Indicates that this sentence is supported by GPS.NET.
		/// </summary>
		public override bool IsSupported
		{
			get
			{
				return true;
			}
		}

		#endregion

		#region Static Members

		public static readonly PgrmeSentence Empty = new PgrmeSentence(Distance.Empty,
			Distance.Empty, Distance.Empty);

		public static PgrmeSentence Parse(string sentence)
		{
			return new PgrmeSentence(sentence);
		}

		#endregion
	}
}
